Service的启动过程(一)

Service介绍

Service是Android的四大组件之一,官方对它的描述是

A Service is an application component representing either an application’s desire to perform a longer-running operation while not interacting with the user or to supply functionality for other applications to use.

大概意思为,Service是一个应用程序组件,它是在一个应用程序不和用户进行交互时在后台执行的一个长时间运行的操作,或者为其他应用进程所使用的功能模块(这里应该是说Service可以被Activity或者其他应用进行bindService)。总之,我们对于Service的理解就是它是一个可以在后台运行不和用户进行交互的应用组件。

在刚开始接触Service,貌似觉得Service和Thread有些类似,后面随着深入了解后,才发现Service和Thread完全是两回事,那么它和Thread的区别在哪里?我觉得主要由以下几点:

  1. Service作为Android组件,有它自己的声明周期,而Thread是操作系统中的概念,它是CPU分配时间片的最小单元。

  2. Service是可以被其他组件进行操作的,比如Activity,而Thread不可以。

  3. Service是运行于主线程上的,作为remote Service后,它是运行在独立的进程中的main线程上的,而Thread的运行是独立的,在new Thread后就于它所在的线程无关了。

Service的启动方式

startService

通过startService启动的Service会一直在后台运行,直到手动stopService或者stopSelf,这种方式启动的Service不和Activity组件进行交互,它经历的生命周期为onCreate->onStartCommand->onDestroy

bindService

通过bindService可以将Service和其他应用组件进行绑定,这时Service是以Server的形式为其提供服务的,绑定Service的组件可以调用Service提供的方法,这种方式同启动方式不同,绑定的service的生命周期通常只是在为组件提供服务时处于运行状态,并不时一直在后台运行,组件解除绑定后,service相应的就被销毁了。bindService的生命周期为 onCreate->onBind->onUnbind->onDestroy,需要注意的时多次bindService后只需要一次unbind即可.

远程服务

当在AndroidMainfest的Service标签中中指定了android:process时,代表Service将运行于独立的进程中。这时候如果通过bindService绑定服务可能就需要借助于AIDL了(Messenger也是可以的)。 否则组件和Sevice运行在相同的进程中,这时候只需要在服务端拓展Binder类后返回即可。

Service绑定和启动的转换

Service的绑定和启动是可以同时进行的,即可以同时通过startService和bindService对其进行调用,这时候按照先后顺序有不同的结果。

先绑定后再启动

这种方式启动后service,Service转为启动方式,也就是服务运行不受绑定组件的限制,会一直在后台运行,直到stopService或者stopSelf。

先启动后在绑定

这种情况下,Service先是以启动方式运行在后台,当组件对Service进行绑定后,仍然可以对Service继续请求操作,只是解除绑定后,Service依然会在后台继续运行,不受解绑的影响。

startService的源码分析

接下来,我们将通过阅读Service的源码来进一步了解Android中的Service是如果启动的。startService是从ContextImpl开始的,它是Context上下文的实现类,我们的Activity继承自ContextThemeWrapper,后者又继承自ContextWrapper,在ContextWrapper中有个Context的mBase成员,它实际上就是ContextImpl,因为Context只是一个抽象类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//Service的启动状态流程 
@Override
public ComponentName startService(Intent service) {
warnIfCallingFromSystemProcess();
return startServiceCommon(service, mUser);
}

private ComponentName startServiceCommon(Intent service, UserHandle user) {
try {
validateServiceIntent(service);//校验service的Intent
service.prepareToLeaveProcess();
//通过AMS的binder代理进行IPC调用
/**这里对参数进行说明:
* mMainThread.getApplicationThread(): 是个ApplicationThread对象,它是个Binder server
* 这里将它传递给AMS,AMS使用它和应用程序进行交互。
* service:要启动的service的intent
* service.resolveTypeIfNeeded(getContentResolver()):MIME类型,未指定为null
* user.getIdentifier:启动进程的用户id
* */
ComponentName cn = ActivityManagerNative.getDefault().startService(
mMainThread.getApplicationThread(), service,
service.resolveTypeIfNeeded(getContentResolver()), user.getIdentifier());
……
return cn;
} catch (RemoteException e) {
return null;
}
}

startService开始调用startServiceCommon,在startServiceCommon中一开始先进行Intent的校验,在Android 4.4中对service的隐式启动做了安全警告,而在Android 5.1禁止通过隐式方式来启动service,接下来就是通过IPC Binder调用AMS的startService调用过程,这里需要注意传递的参数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//AMS端启动service
public ComponentName startService(IApplicationThread caller, Intent service,String resolvedType, int userId) {
enforceNotIsolatedCaller("startService");
……
synchronized(this) {
final int callingPid = Binder.getCallingPid();//调用者进程的pid
final int callingUid = Binder.getCallingUid();//调用者进程的uid
//这里清理调用者进程的uid和pid并将其保存在origId中,设置为当前进程的uid和pid,这是为了方便
//Binder server在当前进程中调用该进程的其他组件
final long origId = Binder.clearCallingIdentity();
//进一步调用startServiceLocked,这里的mServices为ActivityService,AMS使用它来管理应用端的service
ComponentName res = mServices.startServiceLocked(caller, service,
resolvedType, callingPid, callingUid, userId);
Binder.restoreCallingIdentity(origId);//还原调用者的pid和uid
return res;
}
}

在AMS的startService中进一步调用startServiceLocked并传递给其调用者pid和uid信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
//service的启动核心过程
ComponentName startServiceLocked(IApplicationThread caller,
Intent service, String resolvedType,
int callingPid, int callingUid, int userId) {

final boolean callerFg;//代表是否是前台启动的
if (caller != null) {
//这里先通过caller获取到调用者的进程信息,放在ProcessRecord中
final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
if (callerApp == null) {
throw new SecurityException(
"Unable to find app for caller " + caller
+ " (pid=" + Binder.getCallingPid()
+ ") when starting service " + service);
}
callerFg = callerApp.setSchedGroup != Process.THREAD_GROUP_BG_NONINTERACTIVE;
} else {
callerFg = true;
}

//通过service intent获取到AndroidManifest中关于service定义的详细信息
ServiceLookupResult res =
retrieveServiceLocked(service, resolvedType,
callingPid, callingUid, userId, true, callerFg);
if (res == null) {
return null;
}
if (res.record == null) {
return new ComponentName("!", res.permission != null
? res.permission : "private to package");
}
//从获取的ServiceLookupResult中取到ServiceRecord
ServiceRecord r = res.record;
//检查权限
NeededUriGrants neededGrants = mAm.checkGrantUriPermissionFromIntentLocked(
callingUid, r.packageName, service, service.getFlags(), null);
if (unscheduleServiceRestartLocked(r, callingUid, false)) {
if (DEBUG_SERVICE) Slog.v(TAG, "START SERVICE WHILE RESTART PENDING: " + r);
}
r.lastActivity = SystemClock.uptimeMillis();
r.startRequested = true;
r.delayedStop = false;
r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
service, neededGrants));

final ServiceMap smap = getServiceMap(r.userId);
boolean addToStarting = false;
if (!callerFg && r.app == null && mAm.mStartedUsers.get(r.userId) != null) {
ProcessRecord proc = mAm.getProcessRecordLocked(r.processName, r.appInfo.uid, false);
if (proc == null || proc.curProcState > ActivityManager.PROCESS_STATE_RECEIVER) {
if (r.delayed) {
return r.name;
}
if (smap.mStartingBackground.size() >= mMaxStartingBackground) {
smap.mDelayedStartList.add(r);
r.delayed = true;
return r.name;
}
addToStarting = true;
} else if (proc.curProcState >= ActivityManager.PROCESS_STATE_SERVICE) {
addToStarting = true;
}
}
……
//进一步启动service
return startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
}

首先通过调用者的信息获取到进程信息callerApp,随后通过retrieveServiceLocked获取到解析的Service在AndroidManifest的信息。在这个方法里会为Service创建ServiceRecord它在AMS端代表了当前启动的service,随后初始化了一些信息,比如将startRequested置为true表示请求进行启动service,第一次启动service时r.app是未绑定到ProcessRecord上的,通过getProcessRecordLocked获取service的进行信息,如果未指定android:process时,那么默认是在当前应用进程中启动。随后调用startServiceInnerLocked进一步启动service。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
ComponentName startServiceInnerLocked(ServiceMap smap, Intent service,
ServiceRecord r, boolean callerFg, boolean addToStarting) {
ProcessStats.ServiceState stracker = r.getTracker();
……
//进一步启动service,这里会做一些实质性的工作
String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false);
……
return r.name;
}

//在这里面会做一些service启动的实质性工作
private final String bringUpServiceLocked(ServiceRecord r,
int intentFlags, boolean execInFg, boolean whileRestarting) {
//r.app和 r.app.thread不为null,说明service已经启动了,
//这时候通过sendServiceArgsLocked进一步通知应用端
if (r.app != null && r.app.thread != null) {
sendServiceArgsLocked(r, execInFg, false);
return null;
}
……
if (mRestartingServices.remove(r)) {//正在启动service,就将其从重启列表中移除
clearRestartingIfNeededLocked(r);
}
……

//如果设置了isolatedProcess,服务会在一个特殊的隔离进程下运行,这个进程与系统其他进程分开且没有自己的权限。
final boolean isolated = (r.serviceInfo.flags&ServiceInfo.FLAG_ISOLATED_PROCESS) != 0;
final String procName = r.processName;//进程名,如果有的话
ProcessRecord app;

if (!isolated) {
//获取service所在进程
app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
if (app != null && app.thread != null) {//如果它和应用进程同属一个进程
try {
app.addPackage(r.appInfo.packageName, mAm.mProcessStats);
realStartServiceLocked(r, app, execInFg);//直接启动该service
return null;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when starting service " + r.shortName, e);
}

// If a dead object exception was thrown -- fall through to
// restart the application.
}
} else {
// If this service runs in an isolated process, then each time
// we call startProcessLocked() we will get a new isolated
// process, starting another process if we are currently waiting
// for a previous process to come up. To deal with this, we store
// in the service any current isolated process it is running in or
// waiting to have come up.
app = r.isolatedProc;
}

// Not running -- get it started, and enqueue this service record
// to be executed when the app comes up.
if (app == null) {//如果未找到service相应的进程,则需要为它启动一个单独的进程,进程名字为procName
//这里为service启动进程和为activity启动进程是类似的,都是通过zygote forK出来的。
if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
"service", r.name, false, isolated, false)) == null) {
bringDownServiceLocked(r);
return msg;
}
if (isolated) {
r.isolatedProc = app;
}
}
//注意启动进程的操作是异步的,通知zygote创建进程后将ServiceRecord放到service的等待列表中,
//等进程启动完成后会从该列表取出service运行。
if (!mPendingServices.contains(r)) {
mPendingServices.add(r);
}
……

return null;
}

在startServiceInnerLocked中会调用bringUpServiceLocked进行一些启动的实质性工作,首先会检查ServiceRecord的app和app.thread,如果它们都不为null,说明service已经启动了,这时候走sendServiceArgsLocked的流程,后面我们看到它是如果工作的。

如果service设置了isolatedProcess,那么它会在一个单独的隔离进程中启动,否则通过AMS找到service的进程,如果它和应用进程是同一个进程,那么就直接调用realStartServiceLocked进行service的启动,否则service指定了启动的进程,这时候需要调用startProcessLocked通知zygote为其创建进程,并将其serviceRecord添加到mPendingServices,当进程创建完成后再从其中取出service进行启动流程,这个过程是异步进行的。

下面我们就分别看看这几种情况下的service是如何启动的:

  1. Service未启动的情况,这时候调用startProcessLocked进行启动
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//为应用或者服务创建进程
final ProcessRecord startProcessLocked(String processName,
ApplicationInfo info, boolean knownToBeDead, int intentFlags,
String hostingType, ComponentName hostingName, boolean allowWhileBooting,
boolean isolated, boolean keepIfLarge) {
ProcessRecord app;

……
//开启新的进程
startProcessLocked(app, hostingType, hostingNameStr);
return (app.pid != 0) ? app : null;
}

//开启新进程 同zygote交互
private final void startProcessLocked(ProcessRecord app,
String hostingType, String hostingNameStr) {
……
try {
……
// Start the process. It will either succeed and return a result containing
// the PID of the new process, or else throw a RuntimeException.
//为service或者activity创建新的进程 通过zygote进程执行 创建完成后回调ActivityThread并执行其main方法
Process.ProcessStartResult startResult = Process.start("android.app.ActivityThread",
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, app.info.seinfo, null);
} catch (RuntimeException e) {}
}

对于service进程不存在情况,需要通过zygote未service创建进程,这个过程同应用程序启动是类似的,Zygote未service创建完进程后,会在主线程中执行ActivityThread的main方法。这个主线程实际上就是ui线程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
//为activity 和 service创建完进程后,会在主线程(ui线程)中执行ActivityThread的main方法
public static void main(String[] args) {
SamplingProfilerIntegration.start();
CloseGuard.setEnabled(false);
Environment.initForCurrentUser();
// Set the reporter for event logging in libcore
EventLogger.setReporter(new EventLoggingReporter());
Security.addProvider(new AndroidKeyStoreProvider());
Process.setArgV0("<pre-initialized>");
Looper.prepareMainLooper();//准备Looper循环
ActivityThread thread = new ActivityThread();
thread.attach(false);//这里会通知AMS应用进程启动完毕

if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}

AsyncTask.init();
Looper.loop();//开启Looper循环

throw new RuntimeException("Main thread loop unexpectedly exited");
}
private void attach(boolean system) {
sCurrentActivityThread = this;
mSystemThread = system;
if (!system) {
ViewRootImpl.addFirstDrawHandler(new Runnable() {
@Override
public void run() {
ensureJitEnabled();
}
});
android.ddm.DdmHandleAppName.setAppName("<pre-initialized>",
UserHandle.myUserId());
RuntimeInit.setApplicationObject(mAppThread.asBinder());
IActivityManager mgr = ActivityManagerNative.getDefault();
try {
mgr.attachApplication(mAppThread);//实际上是通知AMS进程启动起来了
} catch (RemoteException ex) {
// Ignore
}
}
……
}

在main方法中会调用ActivityThread的attach方法,这里会通过binder调用AMS的attachApplication,实际上就是让AMS知道这个进程的存在。AMS中的attchApplication只是简单的调用attachApplicationLocked来进行进一步的启动。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
 //在这里会启动等待新进程的activity或者service
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid) {

……
//通知应用进程进行bind
thread.bindApplication(processName, appInfo, providers,
app.instrumentationClass, profileFile, profileFd, profileAutoStop,
app.instrumentationArguments, app.instrumentationWatcher,
app.instrumentationUiAutomationConnection, testMode, enableOpenGlTrace,
isRestrictedBackupMode || !normalMode, app.persistent,
new Configuration(mConfiguration), app.compat, getCommonServicesLocked(),
mCoreSettingsObserver.getCoreSettingsLocked());

……
if (normalMode) {
try {
//通知ActivityStackSupervisor 进程已经创建,这时候需要看由没有要启动的activity
if (mStackSupervisor.attachApplicationLocked(app, mHeadless)) {
didSomething = true;
}
} catch (Exception e) {
badApp = true;//出错
}
}

// Find any services that should be running in this process...
if (!badApp) {
try {
//通知ActivityServices 进程已经创建 这时候看有没有要启动的service
didSomething |= mServices.attachApplicationLocked(app, processName);
} catch (Exception e) {
badApp = true;//出错
}
}
……
}

进程启动后,在AMS一端会去判断是否有需要启动的Activity或者service,之前我们了解到在启动service之前,AMS已经做好了准备,这里就去真正的启动service了。

frameworks/base/services/java/com/android/server/am/ActiveServices.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
//进程创建后会通过这个方法来通知AMS
boolean attachApplicationLocked(ProcessRecord proc, String processName) throws Exception {
boolean didSomething = false;
// Collect any services that are waiting for this process to come up.
if (mPendingServices.size() > 0) {//看有没有等待启动的服务
ServiceRecord sr = null;
try {
//遍历等待的服务
for (int i=0; i<mPendingServices.size(); i++) {
sr = mPendingServices.get(i);

if (proc != sr.isolatedProc && (proc.uid != sr.appInfo.uid
|| !processName.equals(sr.processName))) {
continue;
}
//从等待队列中移除
mPendingServices.remove(i);
i--;
proc.addPackage(sr.appInfo.packageName, mAm.mProcessStats);
//启动service
realStartServiceLocked(sr, proc, sr.createdFromFg);
didSomething = true;
}
} catch (Exception e) {
Slog.w(TAG, "Exception in new application when starting service "
+ sr.shortName, e);
throw e;
}
}
……
return didSomething;
}

在ActiveServices的attachApplicationLocked方法中会去从等待列表中取出要启动的service,然后通过realStartServiceLocked来进行真正的启动

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
//这里是AMS中启动Service的最后一步,完成收尾工作
private final void realStartServiceLocked(ServiceRecord r,
ProcessRecord app, boolean execInFg) throws RemoteException {
……
r.app = app;
r.restartTime = r.lastActivity = SystemClock.uptimeMillis();

app.services.add(r);
bumpServiceExecutingLocked(r, execInFg, "create");
mAm.updateLruProcessLocked(app, false, null);
mAm.updateOomAdjLocked();//更新oom_adj,这个代表了该进程的优先级

boolean created = false;
try {
String nameTerm;
int lastPeriod = r.shortName.lastIndexOf('.');
nameTerm = lastPeriod >= 0 ? r.shortName.substring(lastPeriod) : r.shortName;

synchronized (r.stats.getBatteryStats()) {
r.stats.startLaunchedLocked();
}
mAm.ensurePackageDexOpt(r.serviceInfo.packageName);
app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
//通知应用进程创建Service
app.thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
app.repProcState);
r.postNotification();
created = true;
} finally {
if (!created) {
app.services.remove(r);
r.app = null;
scheduleServiceRestartLocked(r, false);
}
}

requestServiceBindingsLocked(r, execInFg);
……
//通知service进行onStartCommand
sendServiceArgsLocked(r, execInFg, true);

……
}

在realStartService中会通过IApplicationThread通知应用端服务的启动,在scheduleCreateService的IPC调用中,最终会触发service的onCreate回调。而在sendServiceArgsLocked会触发onStartCommand的回调,至此,service在ASM一端的启动过程就完成了。

  1. 当service的进程已经存在,那么直接调用realStartServiceLocked进行启动即可。
  2. 当service已经启动,这时候需要调用sendServiceArgsLocked来进一步完成启动,这里主要是回调onStartCommand
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
private final void sendServiceArgsLocked(ServiceRecord r, boolean execInFg,
boolean oomAdjusted) {
final int N = r.pendingStarts.size();
if (N == 0) {
return;
}

while (r.pendingStarts.size() > 0) {
try {
ServiceRecord.StartItem si = r.pendingStarts.remove(0);
if (si.intent == null && N > 1) {
// If somehow we got a dummy null intent in the middle,
// then skip it. DO NOT skip a null intent when it is
// the only one in the list -- this is to support the
// onStartCommand(null) case.
continue;
}
si.deliveredTime = SystemClock.uptimeMillis();
r.deliveredStarts.add(si);
si.deliveryCount++;
if (si.neededGrants != null) {
mAm.grantUriPermissionUncheckedFromIntentLocked(si.neededGrants,
si.getUriPermissionsLocked());
}
bumpServiceExecutingLocked(r, execInFg, "start");
if (!oomAdjusted) {
oomAdjusted = true;
mAm.updateOomAdjLocked(r.app);
}
int flags = 0;
if (si.deliveryCount > 1) {
flags |= Service.START_FLAG_RETRY;
}
if (si.doneExecutingCount > 0) {
flags |= Service.START_FLAG_REDELIVERY;
}
//通知应用端服务启动参数
r.app.thread.scheduleServiceArgs(r, si.taskRemoved, si.id, flags, si.intent);
} catch (RemoteException e) {
break;
} catch (Exception e) {
break;
}
}
}

实际上这里是通过IApplicationThread回调应用端的scheduleServiceArgs方法,这是一个Binder的IPC调用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
 public final void scheduleServiceArgs(IBinder token, boolean taskRemoved, int startId,
int flags ,Intent args) {
//Service启动参数
ServiceArgsData s = new ServiceArgsData();
s.token = token;
s.taskRemoved = taskRemoved;
s.startId = startId;
s.flags = flags;
s.args = args;

sendMessage(H.SERVICE_ARGS, s);
}

//通知service启动的请求参数,实际上是调用onStartCommand回调
private void handleServiceArgs(ServiceArgsData data) {
Service s = mServices.get(data.token);//根据token取到service实例
if (s != null) {
try {
if (data.args != null) {
data.args.setExtrasClassLoader(s.getClassLoader());
}
int res;
if (!data.taskRemoved) {
res = s.onStartCommand(data.args, data.flags, data.startId);
} else {
s.onTaskRemoved(data.args);
res = Service.START_TASK_REMOVED_COMPLETE;
}

QueuedWork.waitToFinish();

try {
ActivityManagerNative.getDefault().serviceDoneExecuting(
data.token, 1, data.startId, res);
} catch (RemoteException e) {
// nothing to do.
}
ensureJitEnabled();
} catch (Exception e) {
if (!mInstrumentation.onException(s, e)) {
throw new RuntimeException(
"Unable to start service " + s
+ " with " + data.args + ": " + e.toString(), e);
}
}
}
}

可以看到scheduleServiceArgs最终会调用handleServiceArgs来进行onStartCommand的回调。

坚持原创技术分享,您的支持将鼓励我继续创作!